package state;

import particle.core.view.Renderer;
import particle.core.view.View;
import particle.core.view.controls.Container;
import particle.core.view.controls.IControlData;
import state.component.EventListener;
import state.font.FontManager;
import state.util.Hashtable;

public class SystemCanvas {
  private final int DEFAULT_SLEEP_TIME = 100;

  public GameForm frmCurrent = null;
  public GameForm masterForm = null;
  public GameForm lastState = null;

  public boolean isMasterFormHandleKey = true;

  private Midlet mid = null;
  private Transformer transformer = null;
  private KeyRepeatHandle keyRepeatHandle = null;
  private KeyManagement keyManagement = null;
  private GameTimer timer = null;
  private Graphics g = null;
  private EventListener outOfMemoryListener = null;

  private boolean setTouchPadForAllForm = false;
  private boolean debugMode = false;

  private boolean isLockKey = false;

  private View view = null;
  private Container container = null;
  private IControlData controlData = null;
  private ResourceManager resourceManager = null;

  // =========================== Constructor =============================

  public SystemCanvas(View view1, Container container1) {
    this.view = view1;
    this.container = container1;
    resourceManager = new ResourceManager();
    new GameControl() {
      public void perform() {
        init();
      }
    }.setTimeInterval(1).start();

    timer = new GameTimer(DEFAULT_SLEEP_TIME);
    timer.start();
    TimerListener1 timerListener1 = new TimerListener1();
    timer.addTarget(timerListener1);
  }
  
  class TimerListener1 implements TimerListener {
    public void doTask() {
      container.invalidate();
    }
  }

  // =========================== Init =====================================

  public void init() {
    keyRepeatHandle = new KeyRepeatHandle(this);
    keyRepeatHandle.start();
    keyManagement = new KeyManagement();

    GameGlobal.alert = (GameAlert) GameAlert.instance();
    GameGlobal.alert.setAutoHideInEvent(true);
    transformer = new Transformer();
  }
  
  public ResourceManager getResourceManager() {
    return resourceManager;
  }
  
  public void setResourceManager(ResourceManager resourceManager1) {
    this.resourceManager = resourceManager1;
  }

  public void setOutOfMemoryListener(EventListener outOfMemoryListener1) {
    this.outOfMemoryListener = outOfMemoryListener1;
  }

  public Container getContainer() {
    return container;
  }

  public View getView() {
    return view;
  }

  public IControlData getControlData() {
    return controlData;
  }

  public void setControlData(IControlData controlData1) {
    this.controlData = controlData1;
  }

  public void processOnOutOfMemory() {
    if (debugMode) {
      System.out.println("Incase OutOfMemory, try to release resources...");
    }
    ResourceManager.clearIDLEResource();
    System.gc();
    if (outOfMemoryListener != null) {
      outOfMemoryListener.onActionPerform(null);
    }
  }

  public void setTimerDelay(int delay) {
    timer.setDelay(delay);
  }

  public void resetTimerDelay() {
    timer.setDelay(DEFAULT_SLEEP_TIME);
  }

  public boolean isSetTouchPadForAllForm() {
    return setTouchPadForAllForm;
  }

  public void setSetTouchPadForAllForm(boolean isSetTouchPadForAllForm) {
    this.setTouchPadForAllForm = isSetTouchPadForAllForm;
  }

  public void setDebugMode(boolean isDebugMode) {
    this.debugMode = isDebugMode;
  }

  public boolean isDebugMode() {
    return debugMode;
  }

  // =========================== Next Form ================================

  /**
   * Tiến hành chuyển sang State tiếp theo có sử dụng các hiệu ứng Transform Các hiệu ứng transoform có thể sử dụng nằm trong class {@link Transformer} <br>
   * Transformer.TRANSFORM_MOVE_LEFT <br>
   * Transformer.TRANSFORM_MOVE_RIGHT <br>
   * Transformer.TRANSFORM_CLIP_WIDE_OPEN_FROM_CENTER <br>
   * Transformer.TRANSFORM_CLIP_BREAK_OLD_FORM <br>
   * Transformer.TRANSFORM_CLIP_CLOSE_TO_CENTER <br>
   * Transformer.TRANSFORM_CLIP_JOIN_NEW_FORM <br>
   * 
   * @param state - State tiếp theo
   * @param table - Bảng chứa các tham số cần chuyển cho State tiếp theo
   * @param transformType - Kiểu transform xử dụng
   */
  public void nextState1(GameForm state, Hashtable table, int transformType) {
    if (state == frmCurrent) {
      return;
    }

    isLockKey = true;
    if ((frmCurrent != null) && GameAlert.class.toString().equals(frmCurrent.getClass().toString())) {
      hideAlert();
    }
    resetTimerDelay();
    FontManager.resetAllFont();
    if (setTouchPadForAllForm) {
      state._manager.enableTouchPad();
    }
    lastState = frmCurrent;
    transformer.transform(frmCurrent, state, table, transformType);
    isLockKey = false;
  }

  /**
   * Tiến hành chuyển sang State tiếp theo mà không xử dụng hiệu ứng transform
   * 
   * @param state - State tiếp theo
   * @param table - Bảng chứa các tham số cần chuyển cho State tiếp theo
   */
  public void nextState(GameForm state, Hashtable table) {
    if (state == frmCurrent) {
      return;
    }

    if (keyRepeatHandle != null) {
      keyRepeatHandle.keyReleased();
    }

    isLockKey = true;
    if ((frmCurrent != null) && GameAlert.class.toString().equals(frmCurrent.getClass().toString())) {
      hideAlert();
    }
    lastState = frmCurrent;
    frmCurrent = state;
    state.isRunning = true;

    resetTimerDelay();
    FontManager.resetAllFont();
    if (lastState != null) {
      lastState.isRunning = false;
    }

    if (g != null) {
      g.setClip(0, 0, GameConstants.SCREEN_WIDTH, GameConstants.SCREEN_HEIGHT);
    }
    if (setTouchPadForAllForm) {
      state._manager.enableTouchPad();
    }

    state.init(table);
    if ((lastState != null) && (lastState != state)) {
      lastState.detroyAll();
      ResourceManager.clearIDLEResource();
    }
    isLockKey = false;
  }

  public void changeHandleToAlert() {
    frmCurrent = GameGlobal.alert;
  }

  /**
   * Ẩn Alert hiện tại và quay trở lại form nền
   */
  public void hideAlert() {
    if ((frmCurrent != null) && GameAlert.class.toString().equals(frmCurrent.getClass().toString())) {
      frmCurrent = GameGlobal.alert.getParent();
      frmCurrent.removeScreen();
      GameGlobal.alert.detroyAll();
    }
  }

  public void beginTransform() {
    frmCurrent = transformer;
  }

  public void endTransform(GameForm handleState, boolean needToDetroyOldState) {
    frmCurrent = handleState;
    handleState.removeScreen();

    if (needToDetroyOldState) {
      GameForm frmTmp = transformer.getOldState();
      if (frmTmp != null) {
        frmTmp.detroyAll();
      }
    }

    new GameControl() {
      public void perform() {
        frmCurrent.updateFullScreen();
      }
    }.setTimeInterval(100).start();
    transformer.destroy();
  }

  public KeyRepeatHandle getKeyRepeatHandle() {
    return keyRepeatHandle;
  }

  public KeyManagement getKeyManagement() {
    return keyManagement;
  }

  public GameTimer getTimer() {
    return timer;
  }

  /**
   * Lấy Graphic của màn hình
   * 
   * @return Graphic của màn hình
   */
  public Graphics getGraphic() {
    return g;
  }

  /**
   * Lấy midlet của chương trình
   */
  public Midlet getMidlet() {
    return mid;
  }

  public void setMidlet(Midlet midlet) {
    mid = midlet;
  }

  // =========================== Key =======================================

  public void keyPressed(int keyCode) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }
    
    Key.checkGameKey(keyCode);
    if (keyRepeatHandle != null) {
      keyRepeatHandle.keyPressed(keyCode);
    }
    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doKeyPressed(keyCode);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doKeyPressed(keyCode);
      }
    }
    keyManagement.keyPressed(keyCode);
  }

  public void doKeyRepeated(int keyCode) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }

    if (keyRepeatHandle != null) {
      keyRepeatHandle.keyPressed(keyCode);
    }
    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doKeyRepeated(keyCode);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doKeyRepeated(keyCode);
      }
    }
    keyManagement.keyRepeated(keyCode);
  }

  public void keyReleased(int keyCode) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }

    Key.checkGameKey(keyCode);
    if (keyRepeatHandle != null) {
      keyRepeatHandle.keyReleased();
    }
    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doKeyReleased(keyCode);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doKeyReleased(keyCode);
      }
    }
    keyManagement.keyReleased(keyCode);
  }

  public void pointerDragged(int x, int y) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }

    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doPointerDragged(x, y);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doPointerDragged(x, y);
      }
    }
  }

  public void pointerPressed(int x, int y) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }

    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doPointerPressed(x, y);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doPointerPressed(x, y);
      }
    }
  }

  public void pointerReleased(int x, int y) {
    if (isLockKey) {
      System.out.println("Warning: key locked");
      return;
    }

    if (masterForm != null && masterForm.isRunning && isMasterFormHandleKey) {
      masterForm.doPointerReleased(x, y);
    } else {
      if (frmCurrent != null) {
        frmCurrent.doPointerReleased(x, y);
      }
    }
  }

  public void paint(Renderer g1) {
    if (this.g == null) {
      this.g = new Graphics(g1);
    }

    if (frmCurrent != null) {
      frmCurrent.updateFullScreen();
    }

    if (masterForm != null) {
      masterForm.updateFullScreen();
    }
  }

  public void destroy() {
    if (GameGlobal.alert != null) {
      GameGlobal.alert.destroy();
    }
    if (transformer != null) {
      transformer.destroy();
    }
    mid = null;
    if (keyRepeatHandle != null) {
      keyRepeatHandle.cancel();
      keyRepeatHandle = null;
    }
  }

  public void showNotify() {
    if (frmCurrent != null) {
      frmCurrent.updateFullScreen();
    }
  }
}
